﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExaminationTT.Rule;
using ExaminationTT.Model;

namespace ConcreteRules
{


    public class ConsecutiveSemesterConflict : IConflict
    {
        private string _conflitInfo;
        private IRule _rule;
        private List<IExam> _exams;
        private IEnumerable<IStudent> _affectedStudents;
        private int _affectedStudentsCount;

        public ConsecutiveSemesterConflict(IRule r, IEnumerable<IStudent> subs)
        {
            _rule = r;
            _exams = new List<IExam>();
            _affectedStudents = subs;
            _affectedStudentsCount = _affectedStudents.Count();
        }

        #region IConflit Members


        public string ConflictType
        {
            get { return "Conflito Semestres Consecutivos"; }
        }

        public string ConflitcInfo
        {
            get { return _conflitInfo; }
            set { _conflitInfo = value; }
        }

        public string RuleName
        {
            get { return _rule.Name; }
        }

        public ConflictWeight Weight
        {
            get { return ConflictWeight.Critical; }
        }

        public IEnumerable<IStudent> AffectedStudents
        {
            get
            {
                return _affectedStudents;
            }
        }
        public int AffectedStudentsCount
        {
            get { return _affectedStudentsCount; }
        }

        private class ExamIntersectComparator : IEqualityComparer<ISubscription>
        {
            #region IEqualityComparer<ISubscription> Members

            public bool Equals(ISubscription x, ISubscription y)
            {
                return x.Student.Equals(y.Student);
            }

            public int GetHashCode(ISubscription obj)
            {
                return this.GetHashCode();
            }

            #endregion
        }

        #endregion



        public IEnumerable<IExam> Exams
        {
            get { return _exams.ToArray(); }
        }

        public void AddExame(params IExam[] exams)
        {
            _exams.AddRange(exams);
        }
    }
    

    public class ConsecutiveSemesterRule : IRule
    {
        private class SemesterComparer : IEqualityComparer<ICUSemester>
        {

            #region IEqualityComparer<CUSemester> Members

            public bool Equals(ICUSemester x, ICUSemester y)
            {
                return x.Semester.Number - y.Semester.Number <= 1
                    && x.Semester.Number - y.Semester.Number >= -1;
            }

            public int GetHashCode(ICUSemester obj)
            {
                return this.GetHashCode();
            }

            #endregion
        }

        private SemesterComparer _comparer = new SemesterComparer();
        #region IRule Members

        public IConflict EnforceRule(IExam exam1, IExam exam2)
        {
            //primeiro verificamos se os exames são de semestres consecutivos
            if (exam1.CUnit.Semesters.Intersect(exam2.CUnit.Semesters, _comparer).Count() == 0)
                return null;

            //depois verificamos se a sua marcação foi feita entre um periodo de 48 horas
            if (exam1.ExamDate.Subtract(exam2.ExamDate).TotalHours < 24 &&
                exam1.ExamDate.Subtract(exam2.ExamDate).TotalHours > -24)
            {
                IEnumerable<ISubscription> subs = null;
                if ((subs = RulesUtils.GetStudentsIntersectingExams(exam1, exam2)).Count() > 0)
                {
                    //Se sim, criamos um conflito e adicionamos à lista a retornar
                    ConsecutiveSemesterConflict c = new ConsecutiveSemesterConflict(this, new StudentsEnumerable(subs));
                    c.ConflitcInfo = "O Exame de " + exam1.CUnit.Acronym + " viola a regra " + Name + " com o exame de " + exam2.CUnit.Acronym;
                    c.AddExame(exam1, exam2);
                    return c;
                }
            }
            return null;
        }

        public string Name
        {
            get { return "Regra Semestres Consecutivos"; }
        }

        #endregion
    }
}
